﻿@using Covenant.Core
@using Covenant.Models.Grunts
@using Covenant.Models.Covenant
@model Grunt
@{
    Layout = "_GruntLayout";
    ViewData["Title"] = "Grunts";
    IEnumerable<GruntCommand> GruntCommands = ViewBag.GruntCommands;
    IEnumerable<GruntTasking> GruntTaskings = ViewBag.GruntTaskings;
    IEnumerable<GruntTask> GruntTasks = ViewBag.GruntTasks;

    IEnumerable<SelectListItem> childrenSelectList = Model.Children.Select(C =>
    {
        return new SelectListItem { Text = C, Value = C, Selected = true };
    });
}

@section Sheets
{
    <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap" rel="stylesheet">
}

<div class="d-flex justify-content-between flex-wrap flex-md-nowrap pb-2 mb-3">
    <h1 class="h2">Grunt: <span id="grunt-name" class="text-primary">@Html.DisplayFor(model => model.Name)</span></h1>
</div>
@if (!string.IsNullOrEmpty(Model.Note))
{
    <p><b>Note</b>: @Model.Note</p>
}
<ul class="nav nav-tabs mb-3" id="grunt-tab" role="tablist">
    <li class="nav-item">
        <a class="nav-link active" id="info-tab" data-toggle="tab" href="#info" role="tab" aria-controls="info" aria-selected="true">
            <span data-feather="info"></span>
            Info
        </a>
    </li>
    <li class="nav-item">
        <a class="nav-link" id="interact-tab" data-toggle="tab" href="#interact" role="tab" aria-controls="interact" aria-selected="false">
            <span data-feather="terminal"></span>
            Interact
        </a>
    </li>
    <li class="nav-item">
        <a class="nav-link" id="task-tab" data-toggle="tab" href="#task" role="tab" aria-controls="task" aria-selected="false">
            <span data-feather="box"></span>
            Task
        </a>
    </li>
    <li class="nav-item">
        <a class="nav-link" id="taskings-tab" data-toggle="tab" href="#taskings" role="tab" aria-controls="taskings" aria-selected="false">
            <span data-feather="layers"></span>
            Taskings
        </a>
    </li>
</ul>

<div class="tab-content" id="grunt-tab-content">
    <div class="tab-pane fade" id="info" role="tabpanel" aria-labelledby="info-tab">
        <form id="grunt-edit-form" asp-controller="Grunt" asp-action="Edit">
            <div asp-validation-summary="All" class="text-danger"></div>
            <input asp-for="Id" value="@Model.Id" type="hidden" readonly>
            <div class="form-row">
                <input asp-for="OriginalServerGuid" value="@Model.OriginalServerGuid" type="hidden" readonly>
                <input asp-for="GUID" value="@Model.GUID" type="hidden" readonly>
                <div class="form-group col-md-4">
                    <label asp-for="Status"></label>
                    <select asp-for="Status" asp-items="Html.GetEnumSelectList<GruntStatus>()" class="form-control" disabled></select>
                    <input asp-for="Status" value="@Model.Status" class="form-control" type="hidden" readonly>
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="Children"></label><br />
                    <select asp-for="Children" asp-items=@childrenSelectList disabled class="selectpicker show-menu-arrow" multiple data-dropup-auto="false" data-selected-text-format="count > 4"></select>
                    @for (int i = 0; i < Model.Children.Count; i++)
                    {
                        <input asp-for="Children[i]" value="@Model.Children[i]" class="form-control" type="hidden" readonly>
                    }
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-4">
                    <label asp-for="ImplantTemplate.CommType"></label>
                    <select asp-for="ImplantTemplate.CommType" asp-items="Html.GetEnumSelectList<CommunicationType>()" class="form-control" disabled></select>
                    <input asp-for="ImplantTemplate.CommType" value="@Model.ImplantTemplate.CommType" class="form-control" type="hidden" readonly>
                </div>
                @if (Model.ImplantTemplate.CommType == CommunicationType.HTTP)
                {
                    <div class="form-group col-md-4">
                        <label asp-for="ValidateCert"></label>
                        <select asp-for="ValidateCert" class="form-control" disabled>
                            @if (Model.ValidateCert)
                            {
                                <option selected>True</option>
                                <option>False</option>
                            }
                            else
                            {
                                <option>True</option>
                                <option selected>False</option>
                            }
                        </select>
                        <input asp-for="ValidateCert" value="@Model.ValidateCert" class="form-control" type="hidden" readonly>
                    </div>
                    <div class="form-group col-md-4">
                        <label asp-for="UseCertPinning"></label>
                        <select asp-for="UseCertPinning" class="form-control" disabled>
                            @if (Model.UseCertPinning)
                            {
                                <option selected>True</option>
                                <option>False</option>
                            }
                            else
                            {
                                <option>True</option>
                                <option selected>False</option>
                            }
                        </select>
                        <input asp-for="UseCertPinning" value="@Model.UseCertPinning" class="form-control" type="hidden" readonly>
                    </div>
                }
                else
                {
                    <input asp-for="ValidateCert" value="@Model.ValidateCert" class="form-control" type="hidden" readonly>
                    <input asp-for="UseCertPinning" value="@Model.UseCertPinning" class="form-control" type="hidden" readonly>
                }
                @if (Model.ImplantTemplate.CommType == CommunicationType.SMB)
                {
                    <div class="form-group col-md-4">
                        <label asp-for="SMBPipeName"></label>
                        <input asp-for="SMBPipeName" value="@Model.SMBPipeName" class="form-control" readonly>
                    </div>
                }
                else
                {
                    <input asp-for="SMBPipeName" value="@Model.SMBPipeName" class="form-control" type="hidden" readonly>
                }
            </div>
            <input asp-for="ListenerId" value="@Model.ListenerId" type="hidden" readonly>
            <div class="form-row">
                <div class="form-group col-md-4">
                    <label asp-for="DotNetFrameworkVersion"></label>
                    <select asp-for="DotNetFrameworkVersion" asp-items="Html.GetEnumSelectList<Common.DotNetVersion>()" class="form-control" disabled></select>
                    <input asp-for="DotNetFrameworkVersion" value="@Model.DotNetFrameworkVersion" class="form-control" type="hidden" readonly>
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="Integrity"></label>
                    <select asp-for="Integrity" asp-items="Html.GetEnumSelectList<IntegrityLevel>()" class="form-control" disabled></select>
                    <input asp-for="Integrity" value="@Model.Integrity" class="form-control" type="hidden" readonly>
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="Process"></label>
                    <input asp-for="Process" value="@Model.Process" class="form-control" readonly>
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-6">
                    <label asp-for="UserDomainName"></label>
                    <input asp-for="UserDomainName" value="@Model.UserDomainName" class="form-control" readonly>
                </div>
                <div class="form-group col-md-6">
                    <label asp-for="UserName"></label>
                    <input asp-for="UserName" value="@Model.UserName" class="form-control" readonly>
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-4">
                    <label asp-for="IPAddress"></label>
                    <input asp-for="IPAddress" value="@Model.IPAddress" class="form-control" readonly>
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="Hostname"></label>
                    <input asp-for="Hostname" value="@Model.Hostname" class="form-control" readonly>
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="OperatingSystem"></label>
                    <input asp-for="OperatingSystem" value="@Model.OperatingSystem" class="form-control" readonly>
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-6">
                    <label for="set-activation-time">@Html.DisplayNameFor(model => model.ActivationTime)</label>
                    <input id="set-activation-time" name="@Html.DisplayNameFor(model => model.ActivationTime)" value="@Html.DisplayFor(model => model.ActivationTime)" class="form-control" readonly>
                </div>
                <div class="form-group col-md-6">
                    <label for="set-last-checkin">@Html.DisplayNameFor(model => model.LastCheckIn)</label>
                    <input id="set-last-checkin" name="@Html.DisplayNameFor(model => model.LastCheckIn)" value="@Html.DisplayFor(model => model.LastCheckIn)" class="form-control" readonly>
                </div>
            </div>
            <hr />
            <div class="form-row">
                <div class="form-group col-md-4">
                    <label asp-for="Name"></label>
                    <input asp-for="Name" value="@Model.Name" class="form-control">
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-8">
                    <label asp-for="Note"></label>
                    <input asp-for="Note" value="@Model.Note" class="form-control">
                </div>
            </div>
            <div class="form-row">
                <div class="form-group col-md-4">
                    <label asp-for="Delay"></label>
                    <input asp-for="Delay" value="@Model.Delay" class="form-control">
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="JitterPercent"></label>
                    <select asp-for="JitterPercent" class="form-control">
                        @for (int i = 0; i < 100; i++)
                        {
                            @if (Model.JitterPercent == i)
                            {
                                <option selected>@i</option>
                            }
                            else
                            {
                                <option>@i</option>
                            }
                        }
                    </select>
                </div>
                <div class="form-group col-md-4">
                    <label asp-for="ConnectAttempts"></label>
                    <input asp-for="ConnectAttempts" value="@Model.ConnectAttempts" class="form-control">
                </div>
            </div>
            <div class="form-group">
                <label for="set-kill-date">@Html.DisplayNameFor(model => model.KillDate)</label>
                <input type="text" id="set-kill-date" name="@Html.DisplayNameFor(model => model.KillDate)" value="@Html.DisplayFor(model => model.KillDate)" class="form-control">
            </div>
        </form>
        <div class="btn-group" role="group">
            <button type="button" id="grunt-edit-button" class="btn btn-primary"><span data-feather="edit"></span> Edit</button>
            @if (Model.Status == GruntStatus.Hidden)
            {
                <form asp-action="Hide" asp-route-id="@Model.Id">
                    <button type="submit" class="btn btn-success ml-2"><span data-feather="eye"></span> Unhide</button>
                </form>
            }
            else
            {
                <form asp-action="Hide" asp-route-id="@Model.Id">
                    <button type="submit" class="btn btn-warning ml-2"><span data-feather="eye-off"></span> Hide</button>
                </form>
            }
        </div>
    </div>
    <div class="tab-pane fade" id="interact" role="tabpanel" aria-labelledby="interact-tab">
        <div class="modal fade" id="file-modal" tabindex="-1" role="dialog" aria-labelledby="file-modal-label" aria-hidden="true">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="file-modal-label">Select File</h5>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
                        <input id="file-taskname-input" type="hidden" class="form-control">
                        <div class="form-group">
                            <label for="file-upload">File</label>
                            <input type="file" id="file-upload" class="form-control-file">
                        </div>
                        <div class="form-group">
                            <label id="file-name-label" for="file-name-input">Name</label>
                            <input id="file-name-input" class="form-control">
                        </div>
                        <div class="form-group">
                            <label id="file-typename-label" for="file-typename-input">TypeName</label>
                            <input id="file-typename-input" class="form-control">
                        </div>
                        <div class="form-group">
                            <label id="file-methodname-label" for="file-methodname-input">MethodName</label>
                            <input id="file-methodname-input" class="form-control">
                        </div>
                        <div class="form-group">
                            <label id="file-parameters-label" for="file-parameters-input">Parameters</label>
                            <input id="file-parameters-input" class="form-control">
                        </div>
                        <div class="form-group">
                            <label id="file-filepath-label" for="file-filepath-input">FilePath</label>
                            <input id="file-filepath-input" class="form-control">
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                        <button type="button" id="execute-modal" class="btn btn-primary">Execute</button>
                    </div>
                </div>
            </div>
        </div>
        <div class="d-flex flex-column rounded-lg border border-primary bg-dark">
            <div id="interact-scroll" class="grunt-interact overflow-auto bg-dark">
                <div id="interact-accordion" class="accordion w-100">
                    @foreach (var command in GruntCommands)
                    {
                        <div class="card task-card w-100 border-right-0 border-top-1" id="tasking-card-@command.Id">
                            <div class="d-flex flew-row">
                                <div class="col-auto p-0">
                                    <button class="btn btn-link collapsed task-button" type="button" data-toggle="collapse" data-target="#tasking-collapse-@command.Id" aria-expanded="true" aria-controls="tasking-collapse-@command.Id">
                                        <span class="text-muted" data-feather="plus"></span>
                                    </button>
                                </div>
                                <div class="col-auto pl-0 pr-2">
                                    @if (command.GruntTasking == null)
                                    {
                                        <p class="text-info task-text-head">[@command.CommandTime UTC] Command submitted</p>
                                    }
                                    else
                                    {
                                        <p class="text-info task-text-head">[@command.CommandTime UTC] @command.GruntTasking.GruntTask.Name @command.GruntTasking.Status.ToString().ToLower()</p>
                                    }
                                    <p class="text-white task-text-body">(<b>@command.User.UserName</b>) > @command.Command</p>
                                </div>
                            </div>
                            <div class="card-header p-0 border-top-0 border-bottom-0" id="tasking-header-@command.Id"></div>
                            <div class="collapse" id="tasking-collapse-@command.Id" aria-labelledby="tasking-header-@command.Id">
                                <div class="card-body">
                                    @if (command.CommandOutput != null)
                                    {
                                        if (command.GruntTasking != null && command.GruntTasking.GruntTask != null && command.GruntTasking.GruntTask.Name == "ScreenShot")
                                        {
                                            <img style="max-width: 100%" src="data:image/png;base64, @command.CommandOutput.Output" />
                                        }
                                        else
                                        {
                                            <p class="text-white task-text-body" style="white-space:pre-wrap">@command.CommandOutput.Output</p>
                                        }
                                    }
                                    else
                                    {
                                        <p class="text-white task-text-body" style="white-space:pre-wrap"></p>
                                    }
                                </div>
                            </div>
                        </div>
                    }
                </div>
            </div>
            <div class="w-100 border border-primary p-0 m-0">
                <div class="interact-width d-flex flex-row">
                    <div class="d-inline d-flex flex-column justify-content-center text-muted ml-1">
                        <div id="history-up" class="mb-n1 p-0 border-0 hover-white" style="z-index: 1"><span data-feather="chevron-up"></span></div>
                        <div id="history-down" class="mt-n1 p-0 border-0 hover-white"><span data-feather="chevron-down"></span></div>
                    </div>
                    <input class="d-inline form-control form-control-dark bg-dark text-white typeahead pl-1 border-0" id="interact-input" type="text" autocomplete="off" placeholder="Interact..." aria-label="Interact">
                    <button type="button" class="d-inline btn btn-dark rounded-0 border-primary" id="interact-button">Send</button>
                </div>
            </div>
        </div><br /><br /><br /><br /><br />
    </div>
    <div class="tab-pane fade" id="task" role="tabpanel" aria-labelledby="task-tab">
        @{
            await Html.RenderPartialAsync("_GruntTaskingAssignForm", Model);
        }
    </div>
    <div class="tab-pane fade" id="taskings" role="tabpanel" aria-labelledby="taskings-tab">
        @{
            await Html.RenderPartialAsync("../GruntTasking/_GruntTaskingTable", GruntTaskings);
        }
    </div>
</div>

@section Scripts {
    <environment include="Development">
        <script src="~/js/typeahead.bundle.min.js"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/corejs-typeahead/1.2.1/typeahead.bundle.min.js"></script>
    </environment>
    <script src="~/js/bootstrap-datetimepicker.min.js"></script>
    <script type="text/javascript">"use strict";

        $(document).ready(function () {
            $("#grunt-edit-button").click(function() {
                $("#grunt-edit-form").submit();
            });

            function scrollDown() {
                $("#interact-scroll").animate({
                    scrollTop: $("#interact-scroll")[0].scrollHeight
                }, 1000, function () { });
            }

            $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
                scrollDown();
            });

            $('#interact-accordion').on('hide.bs.collapse', function (e) {
                var f = $("#" + e.target.id).parent().find("svg");
                var p = f.parent();
                f.remove();
                p.append("<span class='text-muted' data-feather='plus'></span>");
                feather.replace();
            });

            $('#interact-accordion').on('show.bs.collapse', function (e) {
                var f = $("#" + e.target.id).parent().find("svg");
                var p = f.parent();
                f.remove();
                p.append("<span class='text-muted' data-feather='minus'></span>");
                feather.replace();
            });

            var taskingTable = $('#tasking-table').DataTable({
                "pageLength": 50
            });

            $("#info-tab").tab('show');
            $("#set-kill-date").datetimepicker();

            var cmdHistoryIndex = 0;
            var cmdHistory = [];

            var historyUp = function () {
                if (cmdHistoryIndex == cmdHistory.length && $("#interact-input").val() != "") {
                    cmdHistory.push($("#interact-input").val());
                }
                if (cmdHistoryIndex != 0) {
                    cmdHistoryIndex--;
                    $("#interact-input").val(cmdHistory[cmdHistoryIndex]);
                    $('.typeahead').typeahead('val', cmdHistory[cmdHistoryIndex]);
                }
            };

            var historyDown = function () {
                if (cmdHistoryIndex < cmdHistory.length) {
                    cmdHistoryIndex++;
                    $("#interact-input").val(cmdHistory[cmdHistoryIndex]);
                    $('.typeahead').typeahead('val', cmdHistory[cmdHistoryIndex]);
                }
                else if (cmdHistoryIndex == cmdHistory.length) {
                    cmdHistoryIndex++;
                    $("#interact-input").val("");
                    $('.typeahead').typeahead('val', '');
                }
                else {
                    $("#interact-input").val("");
                    $('.typeahead').typeahead('val', '');
                }
            };

            $("#history-up").click(historyUp);
            $("#history-down").click(historyDown);

            $("#interact-input").keyup(function (event) {
                if (event.keyCode === 13) {
                    $("#interact-button").click();
                }
                if ($(".tt-empty").length == 1) {
                    if (event.keyCode === 38) {
                        historyUp();
                    }
                    else if (event.keyCode === 40) {
                        historyDown();
                    }
                }
            });

            var switchParameters = function (task) {
                $("div.d-none.invisible." + task).removeClass("invisible").removeClass("d-none").addClass("visible");
                $("." + task + " > div > input").prop("disabled", false);
                $("div.visible").not("." + task).removeClass("visible").addClass("invisible").addClass("d-none");
                $("div.invisible > div > input").prop("disabled", true);
            };

            switchParameters($("#set-task option:selected").text());

            $('#set-task').on('change', function () {
                switchParameters($("#set-task option:selected").text());
            });

            $('#submit-task-button').click(function () {
                var task = $("#set-task option:selected").text();
                var filecontrol = $("." + task + " > div > input.form-control-file")[0];
                if (filecontrol === undefined) {
                    $("#task-submit-form").submit();
                }
                else {
                    var file = filecontrol.files[0];
                    var fr = new FileReader();
                    fr.onload = receivedFileBuffer;
                    fr.readAsDataURL(file);
                }

                function receivedFileBuffer() {
                    $("." + task + " > div > input.file-filler").val(fr.result.split(",").pop()).prop("disabled", false);
                    $("." + task + " > div > input.form-control-file").prop("disabled", true);
                    $("#task-submit-form").submit();
                }
            });

            $('.task-button').click(function () {
                var parent = $(this).parent().parent().parent();
                var strFullId = parent.attr("id");
                var strId = strFullId.substring(13);
                var Id = parseInt(strId);
                var bodyp = parent.find(".card-body > p");
                if (!isNaN(Id) && bodyp.text() == "") {
                    connection.on("ReceiveCommandOutput", function (output) {
                        bodyp.text(output);
                    });
                    connection.invoke("GetCommandOutput", Id).catch(function (err) {
                        return console.error(err.toString());
                    });
                }
            });

            var substringMatcher = function (strs) {
                return function findMatches(q, cb) {
                    var matches, substrRegex;

                    // an array that will be populated with substring matches
                    matches = [];

                    // regex used to determine if a string contains the substring `q`
                    substrRegex = new RegExp(q, 'i');

                    // iterate through the pool of strings and for any string that
                    // contains the substring `q`, add it to the `matches` array
                    $.each(strs, function (i, str) {
                        if (substrRegex.test(str) && str.toLowerCase() != q.toLowerCase()) {
                            matches.push(str);
                        }
                    });

                    cb(matches);
                };
            };

            var getHeaderClass = function (event) {
                if (event == null) {
                    return "";
                }
                else if (event.level == 0) {
                    return "text-white task-text-head";
                }
                else if (event.level == 1) {
                    return "text-white task-text-head";
                }
                else if (event.level == 2) {
                    return "text-warning task-text-head";
                }
                else if (event.level == 3) {
                    return "text-info task-text-head";
                }
                else if (event.level == 4) {
                    return "text-danger task-text-head";
                }
                else {
                    return "";
                }
            }

            function statusToName(status) {
                if (status == 0) {
                    return "Uninitialized";
                }
                else if (status == 1) {
                    return "Tasked";
                }
                else if (status == 2) {
                    return "Progressed";
                }
                else if (status == 3) {
                    return "Completed";
                }
                else if (status == 4) {
                    return "Aborted";
                }
            }

            var displayCommandEvent = function (command, taskingEvent) {
                var taskingcard = $("#tasking-card-" + command.id)[0];
                var headerClass = "text-info task-text-head";
                var outp = '';
                if (command.gruntTasking != undefined && command.gruntTasking.gruntTask.name == 'ScreenShot') {
                    outp = '<img style="max-width: 100%" src="data:image/png;base64, ' + $('<div>').text(command.commandOutput.output).html() + '" />';
                }
                else {
                    outp = '<p class="text-white task-text-body" style="white-space:pre-wrap">' + $('<div>').text(command.commandOutput.output).html() + '</p>';
                }
                if (taskingcard !== undefined) {
                    if (taskingEvent !== undefined) {
                        var head = '<p class="' + headerClass + '">' + $('<div>').text(taskingEvent.messageHeader).html() + '</p>';
                        $("#tasking-card-" + command.id + " > div.d-flex > div.pr-2 > p.task-text-head").replaceWith(head);
                    }
                    $("#tasking-card-" + command.id + " > div#tasking-collapse-" + command.id + " > div.card-body > p").replaceWith(outp);
                    feather.replace();
                }
                else {
                    var content = '<div class="card task-card w-100 border-right-0 border-top-1" id="tasking-card-' + command.id + '">' +
                        '    <div class="d-flex flex-row">' +
                        '        <div class="col-auto p-0">' +
                        '            <button class="btn btn-link collapsed task-button" type="button" data-toggle="collapse" data-target="#tasking-collapse-' + command.id + '" aria-expanded="true" aria-controls="tasking-collapse-' + command.id + '">' +
                        '                <span class="text-muted" data-feather="plus"></span>' +
                        '            </button>' +
                        '        </div>' +
                        '        <div class="col-auto pl-0 pr-2">' +
                        '            <p class="' + headerClass + '">' + $('<div>').text(taskingEvent.messageHeader).html() + '</p>' +
                        '            <p class="text-white task-text-body">(<b>' + $('<div>').text(command.user.userName).html() + '</b>) > ' + $('<div>').text(command.command).html() + '</p>' +
                        '        </div>' +
                        '    </div>' +
                        '    <div class="card-header p-0 border-top-0 border-bottom-0" id="tasking-header-' + command.id + '"></div>' +
                        '    <div class="collapse" id="tasking-collapse-' + command.id + '" aria-labelledby="tasking-header-' + command.id + '">' +
                        '        <div class="card-body">' +
                        '            ' + outp +
                        '        </div>' +
                        '    </div>' +
                        '</div>';
                    $("#interact-accordion").append(content);
                    feather.replace();
                    $("#tasking-card-" + command.id + " > div > div > button").click();
                }
                if (command.gruntTasking != undefined) {
                    var d = [
                        "<a href='/grunttasking/interact/" + command.gruntTaskingId + "'>" + command.gruntTasking.name + "</a>",
                        "<a href='/grunt/interact/" + command.gruntId + "'>" + command.grunt.name + "</a>",
                        "<a href='/grunttask/edit/" + command.gruntTasking.gruntTask.id + "'>" + command.gruntTasking.gruntTask.name + "</a>",
                        statusToName(command.gruntTasking.status),
                        "<a href='/covenantuser/edit/" + command.user.id + "'>" + command.user.userName + "</a>",
                        command.command,
                        command.commandTime,
                        command.gruntTasking.completionTime
                    ];
                    var match = taskingTable.rows(function (idx, data, node) {
                        return data[0].includes(command.gruntTasking.name);
                    });
                    if (match[0].length == 0) {
                        taskingTable.row.add(d).draw(false);
                    }
                    else {
                        taskingTable.row(match[0][0]).data(d).draw(false);
                    }
                }
                setTimeout(scrollDown, 500);
            };

            var getNextId = function () {
                var idStr = $("#interact-accordion").children().last()[0].id;
                var str = idStr.substring(idStr.lastIndexOf("-") + 1);
                return parseInt(str) + 1;
            };

            var displayOutput = function (command) {
                var id = "output-" + getNextId();
                displayCommandEvent(command, undefined);
            }

            var hasTypedAhead = false;
            var connection = new signalR.HubConnectionBuilder().withUrl("/gruntHub").build();

            connection.on("ReceiveCommandEvent", displayCommandEvent);
            connection.on("ReceiveCommandOutput", displayOutput);

            connection.on("ReceiveSuggestions", function (suggestions) {
                if (!hasTypedAhead) {
                    $(".typeahead").typeahead({
                        hint: true,
                        highlight: true,
                        minLength: 1
                    },
                        {
                            name: 'suggestions',
                            limit: 20,
                            source: substringMatcher(suggestions)
                        });
                    hasTypedAhead = true;
                }
            });

            connection.start()
                .then(function () {
                    connection.invoke("JoinGroup", $("#grunt-name").text()).catch(function (err) {
                        return console.error(err.toString());
                    });
                    connection.invoke("GetSuggestions", $("#grunt-name").text()).catch(function (err) {
                        return console.error(err.toString());
                    });
                });

            function getInteract(input) {
                connection.invoke("GetInteract", $("#grunt-name").text(), input).catch(function (err) {
                    return console.error(err.toString());
                });
                event.preventDefault();
            }

            $("#execute-modal").click(function () {
                var file = $("#file-upload")[0].files[0];
                var fr = new FileReader();
                fr.onload = receivedFileBuffer2;
                fr.readAsDataURL(file);

                function receivedFileBuffer2() {
                    var taskname = $("#file-taskname-input").val();
                    var input = "";
                    if (taskname == "Assembly") {
                        input = "Assembly " + $("#file-name-input").val() + " " + fr.result.split(",").pop() + " " + $("#file-parameters-input").val();
                    }
                    else if (taskname == "Assembly") {
                        input = "AssemblyReflect " + $("#file-name-input").val() + " " + fr.result.split(",").pop() + " " + $("#file-typename-input").val() + " " + $("#file-methodname-input").val() + " " + $("#file-parameters-input").val();
                    }
                    else if (taskname == "Upload") {
                        input = "Upload " + $("#file-filepath-input").val() + " " + fr.result.split(",").pop();
                    }
                    else if (taskname == "PowerShellImport") {
                        if (fr.result.indexOf(",") != -1) {
                            input = "PowerShellImport " + $("#file-filepath-input").val() + " " + fr.result.split(",").pop();
                        }
                        else {
                            input = "PowerShellImport ";
                        }
                    }
                    $("#interact-input").val("");
                    $("#file-modal").modal('hide');
                    getInteract(input);
                }
            });

            $("#interact-button")[0].addEventListener("click", function (event) {
                var input = $("#interact-input").val();
                if ($("#interact-input").val() != "") {
                    cmdHistory.push(input);
                    cmdHistoryIndex++;
                }
                var split = input.split(" ");
                var includesName = input.substr(input.indexOf(" ") + 1);
                var onlyCommand = includesName.substr(includesName.indexOf(" ") + 1);
                if (split.length > 0 && (split[0].toLowerCase() == "assembly" || split[0].toLowerCase() == "assemblyreflect" || split[0].toLowerCase() == "upload" || split[0].toLowerCase() == "powershellimport")) {
                    if (split[0].toLowerCase() == "assembly") {
                        $("#file-taskname-input").val("Assembly");
                        $("#file-name-input").prop("hidden", false);
                        $("#file-name-label").prop("hidden", false);
                        $("#file-typename-input").prop("hidden", true);
                        $("#file-typename-label").prop("hidden", true);
                        $("#file-methodname-input").prop("hidden", true);
                        $("#file-methodname-label").prop("hidden", true);
                        $("#file-parameters-input").prop("hidden", false);
                        $("#file-parameters-label").prop("hidden", false);
                        $("#file-filepath-input").prop("hidden", true);
                        $("#file-filepath-label").prop("hidden", true);

                        $("#file-name-input").val(split[1]);
                        $("#file-parameters-input").val(onlyCommand);
                    }
                    else if (split[0].toLowerCase() == "assemblyreflect") {
                        $("#file-taskname-input").val("AssemblyReflect");
                        $("#file-name-input").prop("hidden", false);
                        $("#file-name-label").prop("hidden", false);
                        $("#file-typename-input").prop("hidden", false);
                        $("#file-typename-label").prop("hidden", false);
                        $("#file-methodname-input").prop("hidden", false);
                        $("#file-methodname-label").prop("hidden", false);
                        $("#file-parameters-input").prop("hidden", false);
                        $("#file-parameters-label").prop("hidden", false);
                        $("#file-filepath-input").prop("hidden", true);
                        $("#file-filepath-label").prop("hidden", true);

                        $("#file-name-input").val(split[1]);
                        $("#file-parameters-input").val(onlyCommand);
                    }
                    else if (split[0].toLowerCase() == "upload") {
                        $("#file-taskname-input").val("Upload");
                        $("#file-name-input").prop("hidden", true);
                        $("#file-name-label").prop("hidden", true);
                        $("#file-typename-input").prop("hidden", true);
                        $("#file-typename-label").prop("hidden", true);
                        $("#file-methodname-input").prop("hidden", true);
                        $("#file-methodname-label").prop("hidden", true);
                        $("#file-parameters-input").prop("hidden", true);
                        $("#file-parameters-label").prop("hidden", true);
                        $("#file-filepath-input").prop("hidden", false);
                        $("#file-filepath-label").prop("hidden", false);

                        $("#file-filepath-input").val(split[1]);
                    }
                    else if (split[0].toLowerCase() == "powershellimport") {
                        $("#file-taskname-input").val("PowerShellImport");
                        $("#file-name-input").prop("hidden", true);
                        $("#file-name-label").prop("hidden", true);
                        $("#file-typename-input").prop("hidden", true);
                        $("#file-typename-label").prop("hidden", true);
                        $("#file-methodname-input").prop("hidden", true);
                        $("#file-methodname-label").prop("hidden", true);
                        $("#file-parameters-input").prop("hidden", true);
                        $("#file-parameters-label").prop("hidden", true);
                        $("#file-filepath-input").prop("hidden", true);
                        $("#file-filepath-label").prop("hidden", true);
                    }

                    $("#file-name-input").val(split[1]);
                    $("#file-modal").modal();
                }
                else {
                    $('.typeahead').typeahead('close');
                    $("#interact-input").val("");
                    $(".tt-hint").val("");
                    getInteract(input);
                }
            });
        });</script>
}
